<?php
/*
 * $this->get('request')->getBasePath()  Ex : /var/www/Symfony/web
 * $this->get('kernel')->getRootDir()    Ex : /var/www/Symfony/app
 * $this->container->getParameter('kernel.environment')   Ex: dev
 */

namespace Viettrans\FrontBundle\Controller;

use Symfony\Component\HttpFoundation\File\Exception\FileException;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Form\FormError;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

use Viettrans\FrontBundle\Entity\Announcement;
use Viettrans\FrontBundle\Form\AnnouncementType;

use Viettrans\FrontBundle\Form\NoPersist\ContactPoster;
use Viettrans\FrontBundle\Form\NoPersist\Search;
/**
 * Announcement controller.
 *
 * @Route("/announcement")
 */
class AnnouncementController extends Controller {
    public function __construct() {
		$hostParsed = explode(".", $_SERVER['HTTP_HOST']);
		if(is_array($hostParsed) && in_array($hostParsed[0], array('fr'))) $this->session->setLocale($hostParsed[0]);
	}
	
	/**
     * Lists all Announcement entities.
     * 
     * @Route("/offer/{currentPage}", name="announcement_offer", defaults={"typeId"=1, "currentPage"=1})
     * @Route("/demand/{currentPage}", name="announcement_demand", defaults={"typeId"=2, "currentPage"=1})
     * @Template()
     */
    public function indexAction($typeId, $currentPage) {
        # Get params
        $requestQuery = $this->getRequest()->query;
        
        $params = array(
            'typeId'             => $typeId,
            'currentPage'        => ($currentPage < 1) ? 1 : $currentPage,
            'maxItemsPerPage'    => $this->container->getParameter('max_announcements_per_page'),
			'maxPagesPerSegment' => $this->container->getParameter('max_pages_per_segment'),
            'keyword'            => $requestQuery->get('keyword'),
            'categoryId'         => $requestQuery->get('categoryId'),
            'locality'           => $requestQuery->get('locality'),
            'period'             => $requestQuery->get('period'),
            'numOf'              => $requestQuery->get('numOf'),
            'orderBy'            => $requestQuery->get('orderBy'),
        );
        
        $em = $this->getDoctrine()->getEntityManager();
        $announcements = $em->getRepository('ViettransFrontBundle:Announcement')
                            ->setParams($params)
                            ->getAnnouncements();

        return array(
            'announcements' => $announcements,
        );
    }

    /**
     * Finds and displays a Announcement entity.
     *
     * @Route("/show/{id}", name="announcement_show")
     * @Template()
     */
    public function showAction($id)
    {
        $announcement = $this->getDoctrine()
                             ->getEntityManager()
                             ->getRepository('ViettransFrontBundle:Announcement')
                             ->find($id);

        if (!$announcement) {
            throw $this->createNotFoundException('Không tìm thấy tin đăng tương ứng.');
        }

        # Create the contact poster form
        $form = $this->createForm(new ContactPoster());
        
        # Create the captcha
        $captcha = $this->get('my_captcha_generator');

        return array(
            'announcement' => $announcement,
            'form'         => $form->createView(),
            'captcha'      => $captcha,
        );
    }

    /**
     * Displays a form to create a new Announcement entity.
     *
     * @Route("/new", name="announcement_new")
     * @Template()
     */
    public function newAction() {
        # Create new instance of class Announcement, it's just an empty object
        $announcement = new Announcement();

		# Set default data
		$announcement->setTypeId('1');
		
		# If in the user session then auto-fill some fields
		$userId = $this->get('session')->get('userId');
		$user = $this->getDoctrine()->getEntityManager()->getRepository('ViettransFrontBundle:User')->find($userId);
		if ($user) {
			# Auto-fill
			$announcement->setContactName($user->getName());
			$announcement->setContactEmail($user->getEmail());
			$announcement->setContactTelephone($user->getTelephone());
			$announcement->setLocality($user->getTownObj()->getName().' ('.$user->getTownObj()->getCode().')');
		}
			
        # Get request object
        $request = $this->getRequest();
        
        # Create the form and assign (bind) the form to announcement object
        $form = $this->createForm(new AnnouncementType($this->container), $announcement);

        # Check if the form is submited
        if ('POST' === $request->getMethod()) {
            # Bind the request to the form
            # !!! Important:
            # All the form fields will be filled with the values in request object
            # Since the form is binded to annoucement object, the corresponding properties of annoucement object will be assigned here
            $form->bindRequest($request);
            
            # Check the form validity
            if ($form->isValid()) {
                # Check form data
                $isEverythingOk = true;
                
                # Check Locality. Format: name (code). Ex: Maison Alfort (94140)
                $locality = $announcement->getLocality();
                
                # Get entity manager object
                $em = $this->getDoctrine()->getEntityManager();
                
                # Get Repos
                $townRepo = $em->getRepository('ViettransFrontBundle:Town');
                $deptRepo = $em->getRepository('ViettransFrontBundle:Department');
                $catRepo = $em->getRepository('ViettransFrontBundle:Category');
                $typeRepo = $em->getRepository('ViettransFrontBundle:Type');
                
                # Check type
                $type = $typeRepo->find($announcement->getTypeId());
                
                # If the corresponding type does not exist then show the error
                if (!$type) {
                    $isEverythingOk = false;
                    $form->addError(new FormError('Loại tin không hợp lệ. Bạn phải chọn loại tin trong danh sách.'));
                }
                
                # Check category
                $category = $catRepo->find($announcement->getCategoryId());
                
                # If the category type is not valid then show the error
				# id = 70: Cac danh muc khac / vua la child vua la parent
                if (!$category || ($category->getId() != 70 && $category->getParentId() == 0)) {
                    $isEverythingOk = false;
                    $form->addError(new FormError('Danh mục không hợp lệ. Bạn phải chọn danh mục trong danh sách.'));
                }
                
                # Check locality
                $town = $townRepo->getTownByLocality($locality);

                # If the corresponding town does not exist then show the error
                if (!$town) {
                    $isEverythingOk = false;
                    $form->addError(new FormError('Thành phố không hợp lệ. Bạn phải chọn thành phố trong danh sách gợi ý.'));
                }
                
                # If photo exists then check photo
                $photo = $announcement->getPhoto();
                if (isset($photo)) {
                    # Size is > 1Mb
                    if ($photo->getSize() > 1000000) {
                        $isEverythingOk = false;
                        $form->addError(new FormError('Kích thước ảnh không được vượt quá 1Mb.'));
                    
                    # Format is not valid
                    } elseif(!in_array($photo->getClientMimeType(), array('image/jpeg', 'image/jpg', 'image/png', 'image/gif'))) {
                        $isEverythingOk = false;
                        $form->addError(new FormError('Định dạng ảnh không hợp lệ (.jpeg .jpg .png .gif).'));
                    }
                }
                
                # If everything is ok then show the preview page
                if ($isEverythingOk) {
                    # Get department id
                    $departmentId = substr($town->getCode(), 0, 2);

                    $announcement->setTownId($town->getId());
                    $announcement->setDepartmentId($departmentId);
                    
                    $announcement->setTypeName($type->getName());
                    $announcement->setCategoryName($category->getName());
                     
                    # Upload photo if it exists
                    if (isset($photo)) {
                        # Get uploaded photo file and resize it to the big format
                        # then encoded it to base64 and send it to session variable                    
                        $tmpFile = $photo->getPathName();
                        
                        switch ($photo->getClientMimeType()) {
                            case 'image/jpeg':
                            case 'image/jpg':
                                $srcType = 'jpeg';
                                break;
                            case 'image/png':
                                $srcType = 'png';
                                break;
                            case 'image/gif':
                                $srcType = 'gif';
                                break;
                            default:
                                $srcType = 'jpeg';
                                break;
                        }
                        
                        $myImageGenerator = $this->get('my_image_generator');
                    
                        # If there is no error when upload photo then submit the form
                        try {
                            # !Important : convert the photo and set the photodata to $announcement->photo, so $announcement->photo is a string
                            # Because when upload, $announcement->photo is an object, and why a form try to serialize, we'll have the error
                            $photoData = $myImageGenerator->generate($tmpFile, $srcType, 'jpeg', 480, 360);
                            
                            # Set the session variable
                            $announcement->setPhoto(base64_encode($photoData));

                        # If unable to convert the photo then show the error
                        } catch (Exception $e) {
                            $form->addError(new FormError('Có lỗi khi kiểm tra ảnh. Xin vui lòng kiểm tra lại file ảnh.'));
                        }
                    }
                    
                    # If evething is ok then preview
					# If announcement is posted by user then set userId
					$session = $this->get('session');
					$userId = $session->get('userId');
					if (isset($userId)) $announcement->setUserId($userId);

                    $session->set('announcement', $announcement);
                            
                    return $this->redirect($this->generateUrl('announcement_preview'));
                }
            }
		}
        
        # Render the corresponding view
        return array(
            'form'       => $form->createView(),
        );
    }

    /**
     * Preview a Announcement entity.
     *
     * @Route("/preview", name="announcement_preview")
     * @Template()
     */
    public function previewAction() {
        # Get session object
        $session = $this->get('session');
        
        # If announcement object is empty then redirect to the new page
        if (!$session->has('announcement')) {
            return $this->redirect($this->generateUrl('announcement_new'));
        }
        
        # Get announcement object via session
        $announcement = $session->get('announcement');
        
        # Get the request object
        $request = $this->getRequest();
        
        # Get the method
        $method = $request->getMethod();
        
        # Get the action which is sent via form by post request
        $action = $request->request->get('action');
        
        # Check if the form is submitted, if that is the case then forward to the create page
        if($method == "POST" && $action == "confirm") {
            return $this->redirect($this->generateUrl('announcement_create'));
        }
        
        # Render the view
        return array(
            'announcement' => $announcement,
        );
    }
    
    /**
     * Creates a new Announcement entity.
     *
     * @Route("/create", name="announcement_create")
     */
    public function createAction()
    {
        # Get session object
        $session = $this->get('session');

        # If announcement object is empty then redirect to the new page
        if (!$session->has('announcement')) {
            return $this->redirect($this->generateUrl('announcement_new'));
        }
        
        # Get announcement object via session
        $announcement = $session->get('announcement');

        # Get entity manager object
        $em = $this->getDoctrine()->getEntityManager();
        
        # Check if photo exists
        $photo = $announcement->getPhoto();
        if(isset($photo)) {
            # Generate the photo
            $myImageGenerator = $this->get('my_image_generator');
            
            # Get the image and thumb file path
            $imagesPath = $this->container->getParameter('images_path');
            $randomId = date('his').substr(md5(rand(1, 999)), 0, 6);
			
			# Create folder
			$today = date('Ymd');
			$photoDir = $imagesPath.'/announcement/photo/'.$today;
			$thumbDir = $imagesPath.'/announcement/thumb/'.$today;

			$oldumask = umask(0);
			if (!is_dir($photoDir)) mkdir($photoDir, 0755);
			if (!is_dir($thumbDir)) mkdir($thumbDir, 0755);
			umask($oldumask);

            $photoFilePath = $photoDir.'/'.$randomId.'.jpg';
            $thumbFilePath = $thumbDir.'/'.$randomId.'.jpg'; 
            
            try {
                # Generate photo from base64 data to image
                $myImageGenerator->generateFromBase64($announcement->getPhoto(), $photoFilePath);
                
                # Generate thumb from photo
                $myImageGenerator->generate($photoFilePath,
											$this->container->getParameter('image_extension'),
											$this->container->getParameter('image_extension'),
											$this->container->getParameter('announcement_thumb_max_width'),
											$this->container->getParameter('announcement_thumb_max_height'),
											$this->container->getParameter('announcement_thumb_quality'),
											$thumbFilePath);
    
                # Add photo to announcement
                $announcement->setPhotos($today.'/'.$randomId);
                
            } catch (\Exception $e) {
                # Delete the generated images
                if(file_exists($photoFilePath)) unlink($photoFilePath);
                if(file_exists($thumbFilePath)) unlink($thumbFilePath);
                
                # Remove announcement object
                $session->remove('announcement');
                
                $errDetail = '';
                if ($this->container->getParameter('kernel.environment') == 'dev') $errDetail = $e->getMessage();
                
                $session->setFlash('message', 'Có lỗi khi tải ảnh vào hệ thống.'.$errDetail);
                
                return $this->redirect($this->generateUrl('default_error'));
            }
        }
        
        # Persist announcement to db
        # Begin transaction
		$em->getConnection()->beginTransaction();
		
		try {
            # Persist data to db
            $em->persist($announcement);
            $em->flush();
    
            # Remove announcement object
            $session->remove('announcement');

			# Send activation email
            $message = \Swift_Message::newInstance()
                ->setSubject('Viettrans - Email kích hoạt tin đăng từ Viettrans.net')
                ->setFrom(array(
					'no-reply@viettrans.net' => 'Viettrans'
				))
				->setReplyTo('no-reply@viettrans.net')
                ->setTo(array(
					$announcement->getContactEmail() => $announcement->getContactName()
				))
                ->setBody($this->renderView('ViettransFrontBundle:Email:activateAnnouncement.html.twig', array(
                	'contactName'   => $announcement->getContactName(),
					'activationUrl' => $this->generateUrl('announcement_activate', array(
						'id'    => $announcement->getId(),
						'token' => $this->generateToken($announcement->getId()),
					), true),
                )), 'text/html', 'utf-8');
			
			# If send email successfully
			if ($this->get('mailer')->send($message)) {
				# Commit the transaction
				$em->getConnection()->commit();
				$em->close();
				
				# Set flash message
				$session->setFlash('message', '
					Tin đăng của bạn đã được gửi đi thành công.<br>
					Để kích hoạt tin đăng, xin vui lòng kiểm tra email trong hòm thư mà bạn đã đăng kí và làm theo hướng dẫn.
				');

				return $this->redirect($this->generateUrl('default_success'));
			
			# Error when sending the activation email
			} else {
				# Rollback the transaction
				$em->getConnection()->rollback();
				$em->close();
				
				throw new \Exception('Không gửi được email');  
			}
		
		# Catch the errors
        } catch(\Exception $e) {
            $em->close();
			
			# Remove announcement object
            $session->remove('announcement');

			$errDetail = '';
			if ($this->container->getParameter('kernel.environment') == 'dev') $errDetail = $e->getMessage();
            
            $session->setFlash('message', 'Có lỗi khi tải tin đăng của bạn vào hệ thống. Xin vui lòng liên hệ với admin.'.$errDetail);
                
            return $this->redirect($this->generateUrl('default_error'));
        }
    }
	
	/**
	 * Activate the announcement submitted
	 *
	 * @Route("/{id}/{token}", name="announcement_activate")
	 */
	public function activateAction($id, $token) {
		# Get session object
        $session = $this->get('session');
	
		# Get entity manager object
		$em = $this->getDoctrine()->getEntityManager();
		
		# Token is not valid
		if ($token !== $this->generateToken($id)) {
			$session->setFlash('message', 'Link kích hoạt của bạn không hợp lệ. Xin vui lòng kiểm tra lại thông tin.');
			
			return $this->redirect($this->generateUrl('default_error'));
		
		# Token is valid
		} else {
			# Get announcement object
			$announcement = $em->getRepository('ViettransFrontBundle:Announcement')->find($id);

			if (!$announcement) {
				$session->setFlash('message', 'Tin đăng cần kích hoạt không tồn tại trong hệ thống.');
				
				return $this->redirect($this->generateUrl('default_error'));
			} 
			
			# If announcement has been already activated
			$now = new \DateTime();
			if ($announcement->getIsActivated()) {
				$session->setFlash('message', 'Tin đăng của bạn đã được kích hoạt.');

				return $this->redirect($this->generateUrl('default_success'));
			
			# Activate the announcement
			} else {
				try {
					$now = new \DateTime();
					$announcement->setBeginsAt($now);

					# Get the announcement_expiration date
					$expirationDate = clone $now;
					$expirationDate->modify('+'.$this->container->getParameter('announcement_expiration').' day');
					$announcement->setExpiresAt($expirationDate);

					# Set activated
					$announcement->setActivatedAt($now);
					$announcement->setIsActivated(true);

					$em->persist($announcement);
					$em->flush();
					$em->close();
					
					$session->setFlash('message', 'Tin đăng của bạn đã được kích hoạt thành công.');
				
					return $this->redirect($this->generateUrl('default_success'));

				# In case of error
				} catch (\Exception $e) {
					$session->setFlash('message', 'Có lỗi không xác định khi kích hoạt tin đăng của bạn. Xin vui lòng liên hệ với admin.');
					
					return $this->redirect($this->generateUrl('default_error'));
				}
			}
		}
	}
	
    /**
     * Displays a form to edit an existing Announcement entity.
     *
     * @Route("/{id}/edit", name="announcement_edit")
     * @Template()
     */
    public function editAction($id)
    {
        $em = $this->getDoctrine()->getEntityManager();

        $entity = $em->getRepository('ViettransFrontBundle:Announcement')->find($id);

        if (!$entity) {
            throw $this->createNotFoundException('Unable to find Announcement entity.');
        }

        $editForm = $this->createForm(new AnnouncementType(), $entity);
        $deleteForm = $this->createDeleteForm($id);

        return array(
            'entity'      => $entity,
            'edit_form'   => $editForm->createView(),
            'delete_form' => $deleteForm->createView(),
        );
    }

    /**
     * Edits an existing Announcement entity.
     *
     * @Route("/{id}/update", name="announcement_update")
     * @Method("post")
     * @Template("ViettransFrontBundle:Announcement:edit.html.twig")
     */
    public function updateAction($id)
    {
        $em = $this->getDoctrine()->getEntityManager();

        $entity = $em->getRepository('ViettransFrontBundle:Announcement')->find($id);

        if (!$entity) {
            throw $this->createNotFoundException('Unable to find Announcement entity.');
        }

        $editForm   = $this->createForm(new AnnouncementType(), $entity);
        $deleteForm = $this->createDeleteForm($id);

        $request = $this->getRequest();

        if ('POST' === $request->getMethod()) {
            $editForm->bindRequest($request);

            if ($editForm->isValid()) {
                $em = $this->getDoctrine()->getEntityManager();
                $em->persist($entity);
                $em->flush();

                return $this->redirect($this->generateUrl('announcement_edit', array('id' => $id)));
            }
        }

        return array(
            'entity'      => $entity,
            'edit_form'   => $editForm->createView(),
            'delete_form' => $deleteForm->createView(),
        );
    }

    /**
     * Deletes a Announcement entity.
     *
     * @Route("/{id}/delete", name="announcement_delete")
     * @Method("post")
     */
    public function deleteAction($id)
    {
        $form = $this->createDeleteForm($id);
        $request = $this->getRequest();

        if ('POST' === $request->getMethod()) {
            $form->bindRequest($request);

            if ($form->isValid()) {
                $em = $this->getDoctrine()->getEntityManager();
                $entity = $em->getRepository('ViettransFrontBundle:Announcement')->find($id);

                if (!$entity) {
                    throw $this->createNotFoundException('Unable to find Announcement entity.');
                }

                $em->remove($entity);
                $em->flush();
            }
        }

        return $this->redirect($this->generateUrl('announcement'));
    }

    private function createDeleteForm($id)
    {
        return $this->createFormBuilder(array('id' => $id))
            ->add('id', 'hidden')
            ->getForm()
        ;
    }
	
	private function generateToken($id) {
		$secret = $this->container->getParameter('secret');
		
		return md5($id.$secret);
	}
}
